package main

import (
	"errors"
	"fmt"

	//"iot-base/common/common"
	cpt "iot-base/common/cache/picktemplate"
	"iot-base/common/crudextend"
	"iot-base/common/dbconn"
	"iot-base/common/dbobj"
	"iot-base/common/extendobj"
	"iot-base/common/logger"
	redis "iot-base/common/redis"
	"runtime"
	"strconv"
	"strings"
	"time"

	"gorm.io/gorm"
)

func checkNull(name string, infos map[string]interface{}) (string, error) {
	re, ok := infos[name]

	if ok && re != nil {
		sre := fmt.Sprintf("%v", re)
		return sre, nil
	}
	return "", errors.New(name + " is empty")

}

func init() {
	v, err := redis.IncrBy("g.m_smartBoxForPolice.uid", 1).Result()

	if err != nil {
		logger.SLog.Error("incrby error--------!!!!!!!!!", err)
	}
	if v < 30000 { //可能被清空了redis
		var maxValue int64
		dbconn.DBConnection.Raw(`select max(tp.param_value)  from thing_params  tp where tp.param_id='UID' `).First(&maxValue)
		redis.IncrBy("g.m_smartBoxForPolice.uid", 100+maxValue).Result()
	}
	tempalteRes = make(map[string]interface{})

	refreshDefaultTemplate()
	crudextend.RegisterDveModify("m_smartBoxForPolice", func(msg *crudextend.CrudMsg) crudextend.CrudMsgResp {
		var result crudextend.CrudMsgResp
		if msg != nil {
			if msg.PThing != nil {
				if msg.PThing.ProtocolPath == "" {
					msg.PThing.ProtocolPath = "box"
					result.PThing = msg.PThing
				}
			}
			switch msg.Action {
			case "DELETE":
			case "POST", "PUT":
				ipFound := true
				ip := ""
				uidIndex := -1
				if msg.PThingParams != nil {
					for i, param := range *msg.PThingParams {
						if param.ParamID == "IP" {
							ipFound = true
							ip = param.ParamValue
						} else if param.ParamID == "UID" {
							uidIndex = i
						}
					}
				} else {
					result.Err = errors.New("参数不能为空，请为参数赋值")
					return result
				}
				if ipFound {
					if ip == "" {
						result.Err = errors.New("ip地址不能为空，请为ip赋值")
						return result
					} else {
						count := 0
						dbconn.DBConnection.Raw(`select count(things.uid) 
						from things,thing_params 
						where thing_params.thing_id = things.uid and thing_params.param_id='IP'
						and thing_params.param_value = ? and things.uid != ?`, ip, msg.PThing.UID).Find(&count)
						if count > 0 {
							result.Err = errors.New("ip地址重复，请重新为ip赋值")
							return result
						}
					}
				}
				var uidfordev string
				if uidIndex == -1 {
					sid, _ := redis.IncrBy("g.m_smartBoxForPolice.uid", 1).Result()
					array := *(msg.PThingParams)
					uidfordev = strconv.FormatInt(sid, 10)
					params := append(array,
						dbobj.ThingParam{
							ThingID:    msg.PThing.UID,
							ParamID:    "UID",
							ParamValue: uidfordev,
						})
					result.PThingParams = &params
				} else {
					array := *(msg.PThingParams)
					param := &array[uidIndex]
					if param.ParamValue == "" {
						sid, _ := redis.IncrBy("g.m_smartBoxForPolice.uid", 1).Result()
						fmt.Println("-------create uid --------------", sid)
						param.ParamValue = strconv.FormatInt(sid, 10)
					}

					result.PThingParams = &array

				}

			}
		}
		return result
	})

	crudextend.RegisterStationAction("policeOffice", func(msg *crudextend.StationMsg) crudextend.StationMsgResp {
		var result crudextend.StationMsgResp
		var notinsert []int
		if msg != nil && msg.Infos != nil {
			now := time.Now()
			//var err error
			var stationID string
			var err error
			var ip string
			var name string
			var templateID string
			var lat string
			var lon string
			var bi string

			stationMap := make(map[string]*dbobj.Station)
			ipMap := make(map[string]bool)
			for i, item := range msg.Infos {

				ip, err = checkNull("智能箱IP", item)
				if err != nil || ip == "" {
					//result.Err = err
					notinsert = append(notinsert, i)
					logger.SLog.Error("not insert ip is null", i)
					continue
				}
				_, exist := ipMap[ip]
				if exist {
					notinsert = append(notinsert, i)
					logger.SLog.Error("not insert ip is 在excel中冲突", i)
					continue
				}
				var tp dbobj.ThingParam
				errtp := dbconn.DBConnection.Find("params_id=? and params_value=?", "IP", ip).
					First(&tp).Error
				if errtp == nil { //找到ip地址
					notinsert = append(notinsert, i)
					logger.SLog.Error("not insert ip is 数据库中冲突 冲突的设备id：", tp.UID)
					continue
				}
				ipMap[ip] = true
				stationID, err = checkNull("站点id", item)
				if err != nil {
					logger.SLog.Error("站点id为空：", i)
					result.Err = err
					break
				}
				name, err = checkNull("名称", item)
				if err != nil {
					logger.SLog.Error("名称为空：", i)
					result.Err = err
					break
				}
				templateID, err = checkNull("模板", item)
				if err != nil {
					templateID = "xj.default"
				}

				lon, _ = checkNull("经度", item)

				lat, _ = checkNull("纬度", item)

				bi, _ = checkNull("公安编号", item)

				gateway, _ := checkNull("网关", item)

				mask, _ := checkNull("掩码", item)

				_, ok := stationMap[stationID]
				if !ok {
					var station dbobj.Station
					station.UID = stationID
					err = dbconn.DBConnection.First(&station).Error
					if err != nil {
						result.Err = errors.New(fmt.Sprintf("%d行派出所id无效", i))
						logger.SLog.Error("派出所id无效：", i)
						break
					}
					//pStation = &station
					stationMap[stationID] = &station
				}
				var thing dbobj.Thing
				isNew := (bi == "")
				if bi != "" {
					err = dbconn.DBConnection.Model(&thing).Where("business_id=?", bi).First(&thing).Error
					if err != nil { //没有找到
						isNew = true
						var thingIP dbobj.ThingParam
						err = dbconn.DBConnection.Model(&thingIP).
							Where("param_id=? and param_value=?", "IP", ip).First(&thingIP).Error
						if err == nil {
							if result.Infos == nil {
								result.Infos = make([]map[string]interface{}, 0, 5)
							}
							errmap := map[string]interface{}{"忽略": fmt.Sprintf("%d行", i)}
							result.Infos = append(result.Infos, errmap)
							logger.SLog.Error("not insert bi not empty and ip is empty", i)
							continue
						}
					} else {
						if thing.ModelID != "m_smartBoxForPolice" {
							isNew = true
							thing.AutoID()
						} else {
							isNew = false
						}
					}
				} else {
					var thingIP dbobj.ThingParam
					err = dbconn.DBConnection.Model(&thingIP).
						Where("param_id=? and param_value=?", "IP", ip).First(&thingIP).Error
					if err == nil { //找到了该设备
						isNew = false
						thing.UID = thingIP.ThingID
					}
				}

				thing.SName = name
				thing.Lat = lat
				thing.Lon = lon
				thing.ModelID = "m_smartBoxForPolice"
				thing.ProtocolPath = "box"
				thing.ProxyThingID = ""
				thing.IsProxy = true
				thing.IsStation = false
				thing.StatusUsed = 1
				thing.BusinessID = bi
				//sid, _ := redis.IncrBy("g.m_smartBoxForPolice.uid", 1).Result()
				var params [5]dbobj.ThingParam
				params[0].ParamID = "IP"
				params[0].ParamValue = ip
				//params[1].ParamID = "TemplateID"
				//params[1].ParamValue = templateID
				params[2].ParamID = "gateway"
				params[2].ParamValue = gateway
				params[3].ParamID = "mask"
				params[3].ParamValue = mask

				var ts dbobj.ThingStation

				ts.StationID = stationID
				ts.ModelID = thing.ModelID
				sno := i
				ts.SNO = int(sno)
				var maintainInfo dbobj.ThingMaintainInfo
				maintainInfo.ThingID = thing.UID
				maintainInfo.UsedTime = &now
				maintainInfo.Creator, _ = checkNull("施工单位", item)
				maintainInfo.Maintain, _ = checkNull("运维单位", item)
				//isNew := false
				var uidfordev string
				if (err != nil) || (bi == "" && isNew) { //新建

					maintainInfo.CreateTime = &now
					thing.AutoID()

					dbconn.DBConnection.Create(&thing)
					params[4].ParamID = "UID"
					sid, _ := redis.IncrBy("g.m_smartBoxForPolice.uid", 1).Result()
					uidfordev = strconv.FormatInt(sid, 10)
					params[4].ParamValue = uidfordev
					ts.ThingID = thing.UID
					maintainInfo.ThingID = thing.UID
					ts.SNO = int(sid)
					dbconn.DBConnection.Create(&ts)
					dbconn.DBConnection.Create(&maintainInfo)

				} else {
					//thing.UID =
					ts.ThingID = thing.UID

					dbconn.DBConnection.Save(&thing)
					//dbconn.DBConnection.Save(&ts)
					dbconn.DBConnection.Save(&maintainInfo)
				}
				//dbconn.DBConnection.Where("thing_id=?", thing.UID).Delete(&dbobj.ThingParam{})
				var paramOld dbobj.ThingParam

				for _, param := range params {
					param.ThingID = thing.UID
					if param.ParamID != "" {
						if isNew {
							dbconn.DBConnection.Create(&param)
							continue
						}
						paramOld.UID = 0
						errP := dbconn.DBConnection.Where("thing_id=? and param_id=?", thing.UID, param.ParamID).First(&paramOld).Error
						if errors.Is(errP, gorm.ErrRecordNotFound) {
							dbconn.DBConnection.Create(&param)
						} else {
							if paramOld.ParamValue != param.ParamValue {
								param.UID = paramOld.UID
								dbconn.DBConnection.Save(&param)
							}
						}

					}
				}
				cpt.SetTemplateToThing(thing.UID, templateID)
				Mux.Lock()

				boxmap[uidfordev] = thing.UID
				boxistrue[thing.UID] = uidfordev

				Mux.Unlock()
				AddDevf(uidfordev, ip)

			}
			fmt.Println("line not insert------------------", notinsert)
			logger.SLog.Warn("line not insert------------------", notinsert)
			saveFile()

		}

		return result
	})
	inithandle()
	crudextend.RegisterHTTPAction("m_smartBoxForPolice", extendHTTPFun)
}

type CALL_BACK_FUN func(msg *crudextend.HTTPMsg) crudextend.HTTPMsgResp

var funMap map[string]CALL_BACK_FUN
var g_mobj extendobj.MObj
var tempalteRes map[string]interface{}

func refreshDefaultTemplate() {
	dbconn.DBConnection.Where("s_name=?", "sm_default_template").Find(&g_mobj)
	tempalteRes["body"] = g_mobj.Body
}

func inithandle() {
	funMap = make(map[string]CALL_BACK_FUN)
	funMap["boxipc"] = func(msg *crudextend.HTTPMsg) crudextend.HTTPMsgResp {
		var res crudextend.HTTPMsgResp
		switch msg.Action {
		case "PUT", "POST":
			res.Infos, res.Err = ipcSave(msg.QueryMap)
		case "DELETE":
			res.Infos, res.Err = ipcRemove(msg.QueryMap)
		}
		return res
	}
	funMap["boxipc_batch"] = batchIPCs
	funMap["query_alarm"] = func(msg *crudextend.HTTPMsg) crudextend.HTTPMsgResp {
		var res crudextend.HTTPMsgResp
		switch msg.Action {
		case "GET":
			res.Infos, res.Err = alarmQuery(msg.QueryMap)
			return res
		}
		res.Err = errors.New("命令不支持")
		return res

	}
	funMap["thing_ex"] = func(msg *crudextend.HTTPMsg) crudextend.HTTPMsgResp {
		var res crudextend.HTTPMsgResp
		switch msg.Action {
		case "GET":
			res.Infos, res.Err = getThingEx(msg.QueryMap)
			return res
		}
		res.Err = errors.New("命令不支持")
		return res

	}
	funMap["template"] = func(msg *crudextend.HTTPMsg) crudextend.HTTPMsgResp {
		var res crudextend.HTTPMsgResp
		res.Info = tempalteRes
		switch msg.Action {
		case "PUT":
			refreshDefaultTemplate()
			return res
		case "GET":
			return res
		}
		res.Err = errors.New("命令不支持")
		return res

	}
}

func runHandle(handle func(msg *crudextend.HTTPMsg) crudextend.HTTPMsgResp,
	msg *crudextend.HTTPMsg, res *crudextend.HTTPMsgResp) crudextend.HTTPMsgResp {
	defer func() {
		if err := recover(); err != nil {
			logger.SLog.Error("handle error", err)
			serr := fmt.Sprintf("handle error %v", err)
			var buf [4096]byte
			n := runtime.Stack(buf[:], false)
			//fmt.Printf("==> %s\n", string(buf[:n]))
			logger.SLog.Error("handle error", "stack", string(buf[:n]))
			res.Err = errors.New(serr)
		}

	}()
	return handle(msg)
}

func extendHTTPFun(msg *crudextend.HTTPMsg) crudextend.HTTPMsgResp {
	if msg != nil {

		if msg.QueryMap != nil {
			qtype := msg.QueryMap["ctype"]
			if qtype != "" {
				qtype = strings.TrimSpace(qtype)
			}
			handle := funMap[qtype]
			var res crudextend.HTTPMsgResp
			if handle == nil {

				res.Err = errors.New("参数错误，处理函数为发现 " + qtype)
				return res
			} else {

				result := runHandle(handle, msg, &res)
				if res.Err != nil {
					return res
				}
				return result
			}

		}
	}
	var res crudextend.HTTPMsgResp
	res.Err = errors.New("参数错误，msg 为空")
	return res

}
